module Contour;


import derelict.opengl.glext;
import derelict.opengl.gl;
import derelict.opengl.glu;
import tango.math.Math;
import tango.io.Stdout;


class Contour
{
	float [] silhouette,silhouette_rel;
	float position [2];
	//uint[] shadow_indices;
	GLuint  vboIndiceID;
	GLuint  vboVerticeID;
	uint nVert;
	uint ID;
	
	void initShadowBuffers()
	{
		
		
		Stdout.formatln(" vboIndice : {}",vboIndiceID);
		
		glGenBuffersARB(1, &vboIndiceID);
		Stdout.formatln(" vboIndice : {}",vboIndiceID);
		glGenBuffersARB(1, &vboVerticeID);
		
		int n=silhouette_rel.length/2;
		
		
		GLubyte[] shadow_indices;
		shadow_indices.length=(n+1)*2; // create vertex index array
		uint i,j=0;
		shadow_indices[j++]=0;
		
			
        for (i=0;i<n;i++)
		{
			shadow_indices[j++]=(i+n)%(2*n);
			shadow_indices[j++]=(i+1)%n;
			
		}
		shadow_indices[j]=n;

		// bind VBO in order to use
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboIndiceID);
		
		// upload data to VBO
		glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, shadow_indices.length*GLubyte.sizeof, cast(void*)shadow_indices.ptr, GL_STATIC_DRAW_ARB);

		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
		
		
		// it is safe to delete after copying data to VBO
		//delete [] shadow_indices;
		
	}
	this(uint id,float[][] iPts,bool invert,float [2]pos,float[] color)
	{
		int i,n;
		ID=id;
		position[]=pos;
		nVert=iPts.length;
		n=iPts.length*2;
		silhouette.length=n*2;
		silhouette_rel.length=n;
		
		
		
		if (invert)
		{
			i=0;
			foreach(p;iPts)
			{
				silhouette_rel[i]=p[0]-position[0];
				silhouette_rel[i+1]=p[1]-position[1];
				silhouette[i]=p[0];
				silhouette[i+1]=p[1];
				i+=2;
				
				
			}
		}else
		{
			i=n-1;
			foreach(p;iPts)
			{
				silhouette_rel[i-1]=p[0]-position[0];
				silhouette_rel[i]=p[1]-position[1];
				silhouette[i-1]=p[0];
				silhouette[i]=p[1];
				i-=2;
				
				
			}
		}
		initDL(color);
		initShadowBuffers();
		
	}
	void updatePosition(float[2] pos)
	{
			
		uint i;
		position[]=pos;
		float *p=silhouette.ptr;
		float *pr=silhouette_rel.ptr;
		for (i=0;i<nVert*2;i++)
		{
			*p=*pr+pos[i%2];
			p++;
			pr++;
						
		}
		
		
	}
	void updatePositionAndAngle(float[2] pos,float angle_rad)
	{
		float * p=silhouette_rel.ptr;
		float * p2=silhouette.ptr;
		float c=cos(angle_rad),s=sin(angle_rad);
		float x,y;
		position[]=pos;
		uint j=0;
		//Stdout.formatln(" _______________________________");
			
		for (int i=0;i<nVert;i++)
		{
			x=p[0];
			y=p[1];
			p+=2;
			p2[j++]=-x*s+y*c+position[0];
			//Stdout.format(" x= {},X: {} ",x,p2[j-1]);
			p2[j++]=x*c+y*s+position[1];
			//Stdout.formatln(" y= {},Y: {} ",y,p2[j-1]);
			
			
			
		
		}
			
	}
	bool updateShadow2(float[2] O,float range)
	{
		float r2=range*range*2;
		float dx=O[0]-position[0];
		float dy=O[1]-position[1];
		float d2;
		if ((dx*dx+dy*dy)>r2) return false;
		float* p,p_s;
		float f;
		
		uint n=silhouette_rel.length;
		
		p=silhouette.ptr;
		p_s=p+n;
		for (int i=0;i<n/2;i++)
		{
			dx=p[0]-O[0];
			dy=p[1]-O[1];
			p+=2;
			d2=dx*dx+dy*dy;
			f=(r2/d2);
			f=(f<=1f)?1f:sqrt(f);
			p_s[0]=O[0]+dx*f;
			
			p_s[1]=O[1]+dy*f;
			p_s+=2;
		
		}
		//Stdout.formatln("OK shadow {} because dist = {} {} -> {} ",name,dx,dy,sqrt((dx*dx+dy*dy)));
		return true;	
	
	}
	bool updateShadow(float[2] origin,float range)
	{
		
		if (updateShadow2(origin,range))
		{
			
			glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboVerticeID);
			glBufferDataARB(GL_ARRAY_BUFFER_ARB, silhouette.length*float.sizeof, cast(void*) silhouette.ptr, GL_STREAM_DRAW_ARB);
			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
			return true;
		}
		return false;

	}
	void drawShadow()
	{
		
		// bind VBOs for vertex array and index array
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboIndiceID);
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboVerticeID);

		// do same as vertex array except pointer
		glEnableClientState(GL_VERTEX_ARRAY);                 // activate vertex coords array
		glVertexPointer(2, GL_FLOAT, 0, cast(void*)0);        // last param is offset, not ptr

		uint n=2*nVert+2;
		glDrawElements(GL_TRIANGLE_STRIP, n, GL_UNSIGNED_BYTE, cast(void*)0);

		glDisableClientState(GL_VERTEX_ARRAY);                // deactivate vertex array

		// bind with 0, so, switch back to normal pointer operation
		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
	}
	void initDL(float[] color)
	{
		glNewList(ID*10,GL_COMPILE);
		glColor3f(0f,0.5f,8f);
			
		glBegin(GL_LINE_LOOP);
			int i,n=nVert;
			for (i=0;i<n;i++)
				glVertex2f(silhouette[2*i],silhouette[2*i+1]);
			
		glEnd();
		glEndList();
		
		
	}

	
	void draw()
	{
		glPushMatrix();
        //glTranslatef(position[0],position[1])
        
		glCallList(ID*10);
		glPopMatrix();
		
	}
	
	~this()
	{
		glDeleteBuffersARB(1, &vboIndiceID);
		glDeleteBuffersARB(1, &vboVerticeID);
	}
	
	
}
